//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Base/Include/Common.h"

namespace Engine
{
namespace Base
{

	//
	// Message Template
	//

	template <typename BaseType>
	struct MessageTempl : BaseType
	{
	// types
	public:
		typedef typename BaseType::type_list_t		msg_type_list_t;
		typedef typename BaseType::EType			EType;
		typedef MessageTempl< BaseType >			Self;
		typedef BaseType							base_t;
		

	private:
		struct _MaxSize
		{
			template <usize L, usize R>
			struct Op { static const usize	value = CompileTime::MinMax< usize, L, R >::max; };

			template <typename T, usize Index>
			struct Process { static const usize	value = sizeof(T); };

			static const usize	init_value = 0;
		};

		enum {
			_SIZE = msg_type_list_t::template StaticForEach< _MaxSize, usize >::value
		};

		typedef char	_data_t[ _SIZE ];
		
		typedef void (* _Destructor_t) (void *);


	// variables
	private:
		_Destructor_t	_dtor;
		_data_t			_data;
		EType			_type;


	// methods
	public:
		explicit
		MessageTempl (EType type) : _type(type), _dtor(null)
		{}


		template <typename T>
		MessageTempl (EType type, const T &data) : _type(type), _dtor(null)
		{
			ASSERT( T::IsMessageTypeSupported( _type ) );

			ZeroMem( _data );

			To<T>() = data;
			_dtor   = &_Destructor<T>;
		}
		

		~MessageTempl ()
		{
			if ( _dtor != null )
			{
				_dtor( _data );
				_dtor = null;
			}
		}


		template <typename T>
		T &  To ()
		{
			STATIC_ASSERTE( sizeof(T) <= _SIZE );
			ASSERT( T::IsMessageTypeSupported( _type ) );
			return *(T *)_data;
		}


		template <typename T>
		T const &  To () const
		{
			STATIC_ASSERTE( sizeof(T) <= _SIZE );
			ASSERT( T::IsMessageTypeSupported( _type ) );
			return *(T const *)_data;
		}


		EType		GetType ()	const	{ return _type; }


		void Move (Self &dst)
		{
			dst._data	= this->_data;
			dst._dtor	= this->_dtor;
			dst._type	= this->_type;

			(*this) = Self();
		}
		

	private:
		MessageTempl () : _dtor(null), _type(EType(-1))
		{}


		explicit
		MessageTempl (const Self &) : _dtor(null), _type(EType(-1))
		{}


		void operator = (const Self &) {}
		

		template <typename T>
		static void _Destructor (void *ptr)
		{
			((T *) ptr)->~T();
		}
	};

}	// Base
}	// Engine